<template>
	<view class="pad30">
		<!-- 风险评估 -->
		<view class="box">
			<view class="title"><view/>风险评估</view>
			<view v-html="form.risk_assessment" />
		</view>
		<!-- tab切换 -->
		<view class="box tab">
			<view
				v-for="i, k in ['运动处方', '运动方案']"
				:class="curTabIndex == k && 'active'"
				@click="curTabIndex = k"
			>
			  {{ i }}
			</view>
		</view>
		<view v-show="curTabIndex == 0">
			<!-- 运动处方模板选择 -->
			<view class="box">
				<view class="title"><view/>运动处方模板</view>
				<u-input
					border="surround"
					v-model="curTemplate.title"
					placeholder="请选择运动处方模版"
					disabled
					suffixIcon="arrow-down"
					@tap="pickerShow = true"
				/>
			</view>
			<!-- 选择运动处方模板 -->
			<u-picker
				:show="pickerShow"
				:columns="[templateLi]"
				keyName="title"
				@confirm="(e) => {curTemplate = templateLi[e.indexs[0]]; pickerShow = false}"
				ref="uPicker"
				@cancel="pickerShow = false"
			/>
			<!-- 处方内容 -->
			<view class="box" v-show="curTemplate.content">
				<view class="title"><view/>处方内容</view>
				<editor
					id="editor"
					:class="['ql-container', editorStatus == 'focus' && 'focus']"
					@blur="(e) => editorStatus = e.type"
					@focus="(e) => editorStatus = e.type"
				/>
				<view class="title"><view/>医生签名</view>
				<sign ref="signRef" @uploadFinish="confirmFun" />
			</view>
		</view>
		<!-- 运动方案 -->
		<view class="box" v-if="curTabIndex">
			<view class="title"><view/>AI生成运动方案</view>
			<u-input border="surround" v-model="title" placeholder="请输入运动方案标题，例如：30天减脂计划" clearable />
			<u-button color='#fe5e10' text="AI生成运动方案" :customStyle="{margin: '30rpx auto', width: 'fit-content'}" @click="getAiContent" />
			<u-loading-icon v-if="loading" mode="circle" text="AI正在生成方案，请稍候..." color="#fe5e10" vertical />
			<u-parse v-else-if="form.ai_model_content" class='ql-container' :content="form.ai_model_content" />
		</view>
		<!-- 底部固定保存按钮 -->
		<view class="btn" @click="verifyRequired">保存</view>
	</view>
</template>

<script>
	import sign from "./components/sign.vue";
	import { exerciseTemplates, riskAssessment, savePrescribe, aiChatPrescribe } from "@/api/prescription.js";
	export default {
		components: { sign },
		data() {
			return {
				curTabIndex: 0,
				form: {},
				pickerShow: false,
				templateLi: [],
				curTemplate: {},
				editorCtx: null,
				editorStatus: 'blur',
				title: '',
				loading: false
			}
		},
		watch: {
			curTemplate(val) {
				this.onEditorReady(val.content)
			}
		},
		onLoad(e) {
			this.form.sign = e.sign
			exerciseTemplates().then(res => this.templateLi = res)
			riskAssessment({sign: e.sign}).then(res => this.form.risk_assessment = res)
		},
		methods: {
			// 初始化处方内容HTML
			onEditorReady(html) {
				uni.createSelectorQuery().select('#editor').context((res) => {
					this.editorCtx = res.context
					this.editorCtx.setContents({ html })
				}).exec()
			},
			// AI方案生成
			getAiContent() {
				const title = this.title.replace(/\s/g, "")
				if(!title) {
				  uni.showToast({icon: "none", title: "请输入运动方案标题！", duration: 2000});
				  return;
				}
				this.loading = true
				this.form.title = title
				this.form.ai_model_content = ''
				this.getAiChatPrescribe()
				//aiChatPrescribe(this.form).then(jsonStr => {
					//const lines = jsonStr.split("\n");
					//let fullStr = ''
					// console.log(11, lines)
					// for (let line of lines) {
					// 	if (line == "data: [DONE]") {
					// 		this.loading = false
					// 		this.form.ai_model_content = fullStr
					// 		console.log(11, this.form.ai_model_content)
					// 		return
					// 	}
					// 	if (line.startsWith("data: ")) {
					// 		line = line.replace("data: ", "");
					// 	}
					// 	const parsedData = JSON.parse(line);
					// 	const content = parsedData.Choices?.[0]?.Delta?.Content || "";
					// 	fullStr += content;
					// }
					// this.form.ai_model_content = '<p>小英测试</p>'
				//})
			},
			// 必填信息验证
			verifyRequired() {
				let showTip = false
				if(!this.form.ai_model_content) showTip = true;
				// 运动处方内容
				this.editorCtx.getContents({
					success: (e) => {
						showTip = !(e.text.replace(/[\s\↵]+/g, ""))
						if(showTip) return
						this.form.content = e.html
					}
				})
				if(showTip) {
					uni.showToast({icon: "none", title: "请处理完成！", duration: 2000});
					return
				}
				this.$refs.signRef.finish()
			},
			// 点击保存处方
			confirmFun(url) {
				this.form.signature = url
			  savePrescribe(this.form).then(() => uni.navigateBack())
			},
			// AI方案获取
			getAiChatPrescribe() {
				const _this = this
				const requestTask = uni.request({
					url: 'https://devsaas.hansifit.com/api/dashboard/aichat/prescribe',
					enableChunked: true, //开启 transfer-encoding chunked
					responseType: 'arraybuffer', //设置响应的数据类型。合法值：text、arraybuffer
					method: "POST",
					header: {
						"Content-Type": "application/json;charset=UTF-8",
						"Authorization": uni.getStorageSync("token") && `Bearer ${uni.getStorageSync("token")}`
					},
					data: this.form,
					success(e) {
					}
				});
				
				let accumulatedText = ""; // 存储未处理的流数据
				let fullMessage = ""; // 存储最终拼接的消息
	
				requestTask.onChunkReceived(async (res) => {
					const uint8Array = new Uint8Array(res.data)
					
					// 兼容 TextDecoder 的 UTF-8 解码  微信小程序不支持 const decoder = new TextDecoder("utf-8"); 
					function decodeUTF8(arr) {
						return decodeURIComponent(arr.map(byte => `%${byte.toString(16).padStart(2, "0")}`).join(""));
					}
					// 进行解码
					const chunkText = decodeUTF8([...uint8Array]);
				 
					// 累积数据
					accumulatedText += chunkText;
				 
					// 处理多行 JSON 片段
					const lines = accumulatedText.split("\n");
					accumulatedText = ""; // **暂时清空，后续可能补回**
					
					for (let line of lines) {
						if (line === "data: [DONE]") {
							_this.loading = false // **这里 fullMessage 是完整的内容**
							return; // **提前结束，不再解析后续数据**
						}
						// 去掉 `data: ` 前缀
						if (line.startsWith("data: ")) {
							line = line.replace("data: ", "");
						}
						try {
							const parsedData = JSON.parse(line);
							const content = parsedData.Choices?.[0]?.Delta?.Content || "";
							fullMessage += content; // 累积返回的文本
							//  确保每次解析到新内容时，都执行 onProgress
							_this.form.ai_model_content = fullMessage
						} catch (error) {
							// JSON 解析失败，可能是数据未完全接收，等待下一个 chunk
							accumulatedText += line + "\n"; // **补回未解析的部分**
						}
					}
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
.pad30 {
	padding-bottom: 110rpx;
}
::v-deep .ql-container {
	background: #fafafa;
	border: 2rpx solid #eee;
	border-radius: 16rpx;
	padding: 0 30rpx 30rpx 30rpx;
	height: auto;
	line-height: 2;
	margin-bottom: 30rpx;
	strong, h3 {
		color: #333;
	}
	h3 {
		margin-top: 30rpx;
		font-size: 32rpx;
	}
	li::before {
		color: #fe5e10;
		width: 1em;
	}
	ul {
		padding-left: 20rpx;
	}
	&.focus {
		border-color: #fe5e10;
		background: #fff;
	}
}
.title {
	color: #fe5e10;
	font-size: 34rpx;
	margin-bottom: 30rpx;
	font-weight: bold;
	display: flex;
	align-items: center;
	line-height: 1;
	view {
		width: 8rpx;
		height: 32rpx;
		border-radius: 4rpx;
		background-color: #fe5e10;
		margin-right: 16rpx;
	}
}
.box {
	background-color: #fff;
	border-radius: 24rpx;
	padding: 30rpx;
	margin-bottom: 40rpx;
	box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
	color: #666;
}
.tab {
	display: flex;
	text-align: center;
	padding: 0;
	view {
		flex: 1;
		position: relative;
		padding: 30rpx 0;
		&.active {
			color: #fe5e10;
			font-weight: bold;
			&::after {
				content: "";
				position: absolute;
				bottom: 0;
				left: 50%;
				transform: translateX(-50%);
				width: 40%;
				height: 6rpx;
				background-color: #fe5e10;
				border-radius: 4rpx;
			}
		}
	}
}
.btn {
	color: #fff;
	background: #fe5e10;
	height: 80rpx;
	line-height: 80rpx;
	border-radius: 40rpx;
	text-align: center;
	position: fixed;
	bottom: 30rpx;
	width: calc(100% - 60rpx);
}
</style>